//////////////////////////////////////////////////////////////////////////
//
// This file is a part of XORT project.
//
// PROJECT:         Xort compiler
// FILE:            symtab.cpp
// AUTHOR:          Vladimir Gumenuk
// DATE:            21-Mar-2008
// MODIFICATIONS:
//
//
//     Copyright(c) 2014, Vladimir Gumenuk
//     All rights reserved.
//
//     Redistribution and use in source and binary forms, with or without modification, 
//     are permitted provided that the following conditions are met :
//
//     1. Redistributions of source code must retain the above copyright notice, 
//        this list of conditions and the following disclaimer.
//     2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and 
//        the following disclaimer in the documentation and / or other materials provided with the distribution.
//     3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse 
//        or promote products derived from this software without specific prior written permission.
//
//     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 
//     ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 
//     OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 
//     THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
//     SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 
//     OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
//     HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 
//     OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 
//     EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
//////////////////////////////////////////////////////////////////////////

#include "xort.h"
#include "xcode.h"

#ifdef __XVM__
#include "BuildinObjectInfo.h"
#include "XortStringImpl.h"
xstring * xvm_create_string() {
    xstring *p = new xstring();
    if( p ) p->AddRef();
    return p;
}
#define new_string xvm_create_string() 
#else
#define new_string new string
#endif

const string  cLOCAL_MARKER = "@__local"; // marker for local variables
const string  cFRAME_ENTER  = "@__frameEnter"; // enter new stack frame marker
const string  cFRAME_LEAVE  = "@__frameLeave"; // leave current stack frame and continue with parent

STATIC dword        g_dwTypeID       = 0;
STATIC int          g_iGlobalVarIdx  = 1; // variable xcell index in DATA segment
STATIC int          g_iGlobalProcIdx = 1; // procedure index at functions array
STATIC int          g_iLocalVarIdx   = 1; // index of the object member variable
STATIC int          g_iLocalProcIdx  = 1; // index of the object member procedure
STATIC int          g_iStackVarIdx   = 1; // local stack variable index
STATIC INT_ARRAY    g_arPervStackVarIdx;  // array used to restore stack index after "leave" primitive
STATIC int          g_iArgIdx        = -1;
STATIC STRING_ARRAY g_arLiterals;
STATIC Symbol       g_NULLSymbol;
STATIC SYMBOL_LIST  g_listGlobal;    // global symbol list
STATIC dword        g_dwCompilationFlags = 0;

dword GetCompilationFlags()
{
    return g_dwCompilationFlags;
}

void SetCompilationFlags( dword dwFlags )
{
    g_dwCompilationFlags = dwFlags;
}

string getLocalMarker()
{
    return cLOCAL_MARKER;
}

SymbolRef getNULLSymbol()
{
#ifdef DEBUG
    if( g_NULLSymbol.m_SymKind != sk_nullsymbol )
    {
        Token Tok = lex_GetLastToken();
        x_error( ERR_INTERNAL_COMPILER, Tok.m_dwLine, Tok.m_dwPos );
    }
#endif
    return g_NULLSymbol;
}

SYMBOLLIST GetGlobalSymbolList()
{
    return g_listGlobal;
}

//------------------------------------------------------------------------
// literal pool
//------------------------------------------------------------------------
void lit_Init()
{
    lit_Add( "Experimental Xort compiler. Version 1.0" );
    lit_Add( "Copyright (c) Vladimir Gumenuk. Vinnitsa 2008-2014" );
}

dword lit_Add( string csLiteral ) // returns the literal index
{
#ifdef CPP_COMPILER
    stringref pStr = new_string;
    pStr->Assign( csLiteral.GetBuffer() );
    g_arLiterals.add( pStr );
    #ifdef __XVM__
        pStr->Release();
    #endif
#else
	string pStr;
	pStr.Assign( csLiteral );
    g_arLiterals.add( pStr );
#endif
    return g_arLiterals.count() - 1U;
}

string lit_Get( dword dwIdx )
{
    if( g_arLiterals.count() <= dwIdx ) {
        return "LITERAL NOT FOUND";
    }
#ifdef CPP_COMPILER
    stringref p = g_arLiterals.get( dwIdx );
    return *p;
#else
    string p = g_arLiterals.get( dwIdx );
    return p;
#endif
}

void lit_Free()
{
    g_arLiterals.clear();
}

void lit_DumpLitPool( STRINGARRAY arStr )
{
    dword i = 0;
    dword dwSize = arStr.count();

#ifdef CPP_COMPILER
    message( "\n\n --- Literal pool: %d strings", dwSize );
    while( i < dwSize ) {
        stringref p = arStr.get( i );
        message( "%06d: \"%s\"", i, p->GetBuffer() );
        ++i;
    }
#else
    message( "\n\n --- Literal pool: %@ strings", dwSize );
    while( i < dwSize ) {
        string p = arStr.get( i );
        message( "%@: '%@'", i, p );
        ++i;
    }
#endif
}

void lit_Dump()
{
    lit_DumpLitPool( g_arLiterals );
}

void SaveLiteralPool( FileRef pFile )
{
    dword i = 0;
    dword dwSize = g_arLiterals.count();

    string str = "LITP";
    pFile.WriteString( str );
    pFile.WriteDword( dwSize );

    while( i < dwSize ) {
#ifdef CPP_COMPILER
        stringref p = g_arLiterals.get( i );
        SaveString( *p, pFile );
#else
        SaveString( g_arLiterals.get( i ), pFile );
#endif
        ++i;
    }
}

//------------------------------------------------------------------------
// symbol table
//------------------------------------------------------------------------
dword GenNewTypeCode()
{
    ++g_dwTypeID;
    return g_dwTypeID + t_userobj;
}

void ResetArgIdx()
{
    g_iArgIdx = -1;
}

void ResetLocalIdx()
{
    g_iLocalVarIdx = 1;
    g_iLocalProcIdx = 1;
}

void ResetStackVarIdx()
{
    g_iStackVarIdx = 1;
}

void pushStackVarIdx()
{
    g_arPervStackVarIdx.add( g_iStackVarIdx );
    ++g_iStackVarIdx;
}

void popStackVarIdx()
{
    // statements like continue and break generates the series of leave instructions and this
    /*if( g_arPervStackVarIdx.count() == 0 ) {
        Token Tok = lex_GetLastToken();
        x_error( ERR_INTERNAL_COMPILER, Tok.m_dwLine, Tok.m_dwPos );
        message( "void popStackVarIdx() -> index is negative" );
    }*/
    
    if( g_arPervStackVarIdx.count() > 0 ) {
        g_iStackVarIdx = g_arPervStackVarIdx.get( g_arPervStackVarIdx.count() -1 );
        g_arPervStackVarIdx.del();
    }
}

SymbolRef FindSymbol( SYMBOLLIST symList, string csName, int bLocalOnly )
{
    dword i;
    symList.reset_to_begin();
#ifdef CPP_COMPILER 
    const symbolref *pSym = symList.next();
    while( pSym )
    {
        if( bLocalOnly && ( (*pSym)->m_csName.Compare( cLOCAL_MARKER ) == 0 ) )
        {
            break; // This allows to declare variable with the same name in different scope
        }

        if( (*pSym)->m_csName.Compare( csName ) == 0 ) {
            return **pSym;
        } else if( (*pSym)->m_arAliasNames.count() > 0 ) { // try to find in the aliases
            for( i = 0; i < (*pSym)->m_arAliasNames.count(); ++i ) {
                stringref pcsName = (*pSym)->m_arAliasNames.get( i );
                if( pcsName->Compare( csName ) == 0 ) {
                    return **pSym;
                }
            }
        }

        const symbolref *pPrev = pSym;
        pSym = symList.next();

        if( !pSym ) // begin of list reached, nothing found
        {
            if( (*pPrev)->m_pParent && !bLocalOnly ) // have link to the parent symbol list?
            {
                return FindSymbol( *(*pPrev)->m_pParent, csName, FALSE );
            }
        }
    }
#else
    //DbgPrint( "FindSymbol() -> ENTER" );
    Symbol pSym = symList.next();
    while( pSym )
    {
        if( bLocalOnly && ( pSym.m_csName.Compare( cLOCAL_MARKER ) == 0 ) )
        {
            break; // This allows to declare variable with the same name in different scope
        }

        if( pSym.m_csName.Compare( csName ) == 0 ) {
            //DbgPrint( "FindSymbol() -> LEAVE -> %@", pSym.m_csName );
            return pSym;
        } else if( pSym.m_arAliasNames.count() > 0 ) { // try to find in the aliases
            for( i = 0; i < pSym.m_arAliasNames.count(); ++i ) {
                string pcsName = pSym.m_arAliasNames.get( i );
                if( pcsName.Compare( csName ) == 0 ) {
                    //DbgPrint( "FindSymbol() -> LEAVE -> %@", pSym.m_csName );
                    return pSym;
                }
            }
        }

        Symbol pPrev = pSym;
        pSym = symList.next();

        if( !pSym ) // begin of list reached, nothing found
        {
            if( pPrev.m_pParent && !bLocalOnly ) // have link to the parent symbol list?
            {
                return FindSymbol( pPrev.m_pParent, csName, FALSE );
            }
        }
    }
#endif
    //DbgPrint( "FindSymbol() -> LEAVE -> NULL" );
    return getNULLSymbol();
}

SymbolRef FindType( SYMBOLLIST symList, dword dwType )
{
    symList.reset_to_begin();
#ifdef CPP_COMPILER
    const symbolref *pSym = symList.next();
    while( pSym )
    {
        symbolref pType = *pSym;

        if( pType->m_SymKind == sk_typename || pType->m_SymKind == sk_obj )
        {
            if( dwType == pType->m_dwType ) {
                return *pType;
            }
        }

        const symbolref *pPrev = pSym;
        pSym = symList.next();

        if( !pSym )
        {
            if( (*pPrev)->m_pParent ) // have link to the parent symbol list?
            {
                return FindType( *(*pPrev)->m_pParent, dwType );
            }
        }
    }
#else
    Symbol pSym = symList.next();
    while( pSym )
    {
        if( pSym.m_SymKind == sk_typename || pSym.m_SymKind == sk_obj )
        {
            if( dwType == pSym.m_dwType ) {
                return pSym;
            }
        }

        Symbol pPrev = pSym;
        pSym = symList.next();

        if( !pSym )
        {
            if( pPrev.m_pParent ) // have link to the parent symbol list?
            {
                return FindType( pPrev.m_pParent, dwType );
            }
        }
    }
#endif
    return getNULLSymbol();
}

SymbolRef FindTemplateType( SYMBOLLIST symList, dword dwType, dword dwTemplateSpecType )
{
    symList.reset_to_begin();
#ifdef CPP_COMPILER
    const symbolref *pSym = symList.next();
    while( pSym )
    {
        symbolref pType = *pSym;

        if( pType->m_SymKind == sk_typename || pType->m_SymKind == sk_obj )
        {
            if( dwType == pType->m_dwTemplateType && dwTemplateSpecType == pType->m_dwTemplSpecType ) {
                return *pType;
            }
        }

        const symbolref *pPrev = pSym;
        pSym = symList.next();

        if( !pSym )
        {
            if( (*pPrev)->m_pParent ) // have link to the parent symbol list?
            {
                return FindTemplateType( *(*pPrev)->m_pParent, dwType, dwTemplateSpecType );
            }
        }
    }
#else
    Symbol pSym = symList.next();
    while( pSym )
    {
        if( pSym.m_SymKind == sk_typename || pSym.m_SymKind == sk_obj )
        {
            if( dwType == pSym.m_dwType && dwTemplateSpecType == pSym.m_dwTemplSpecType ) {
                return pSym;
            }
        }

        Symbol pPrev = pSym;
        pSym = symList.next();

        if( !pSym )
        {
            if( pPrev.m_pParent ) // have link to the parent symbol list?
            {
                return FindTemplateType( pPrev.m_pParent, dwType, dwTemplateSpecType );
            }
        }
    }
#endif
    return getNULLSymbol();
}

SymbolRef FindGlobalVarByIndex( SYMBOLLIST symList, dword dwIdx )
{
#ifdef CPP_COMPILER
    SYMBOL_LIST::iterator theIter = symList.end();
    symbolref pSym = (symbolref)theIter;

    while( pSym )
    {
        if( pSym->m_SymKind == sk_var && pSym->m_iIndex == dwIdx )
        {
            return (*pSym);
        }
        theIter--;
        pSym = theIter != NULL ? (symbolref)theIter : NULL;
    }

#else
    SYMBOL_LISTIterator theIter = symList.end();
    Symbol pSym = theIter.prev();

    while( pSym )
    {
        if( pSym.m_SymKind == sk_var && pSym.m_iIndex == dwIdx )
        {
            return pSym;
        }

        pSym = theIter.prev();
    }
#endif
    return getNULLSymbol();
}

int IsLocal( SYMBOLLIST symList )
{
    SymbolRef Loc = FindSymbol( symList, cLOCAL_MARKER, FALSE );
    if( !Loc.isNULL() ) {
        return TRUE;
    }
    return FALSE;
}

void AddAliasName( SymbolRef pBase, string csName )
{
#ifdef CPP_COMPILER
    stringref pcsName = new_string;
    pcsName->Assign( csName );
    pBase.m_arAliasNames.add( pcsName );
    #ifdef __XVM__
        pcsName->Release();
    #endif
#else
    string pcsName;
    pcsName.Assign( csName );
    pBase.m_arAliasNames.add( pcsName );
#endif
}
/*
void CheckStringType()
{
    SymbolRef symStr = FindType( g_listGlobal, t_string );
    if( !symStr.isNULL() ) {
        SymbolRef symAssign = FindSymbol( symStr.m_listMembers, "Assign", TRUE );
        if( !symAssign.isNULL() ) {
            DbgPrint( "!CheckStringType(!) -> %@, members: %@, args: %@", symAssign.m_csName, symAssign.m_listMembers.size(), symAssign.m_dwArgumentsCount );
            if( symAssign.m_listMembers.size() == 0 ) {
                DbgPrint( "FATAL ERROR DETECTED!!!" );
            }
        }
    }
}
*/

SymbolRef AddSymbol( SYMBOLLIST symList, dword sk, string csName, dword dwType, SYMBOL_LIST PTR pParent, SymbolRef pOwner, dword dwModFlags )
{
    int dwStorage = 0;
    int iIdx = 0;

    if( sk == sk_arg ) {
        iIdx = g_iArgIdx;
        --g_iArgIdx;
        dwStorage = cSTORAGE_STACK;
    } else if( sk == sk_var || sk == sk_proc ) { // determine the which idx to use: global or local
        if( !pOwner.isNULL() && ( ( pOwner.m_SymKind == sk_obj ) || ( pOwner.m_SymKind == sk_typename ) ) ) {
            dwStorage = cSTORAGE_MEMBER;
            if( sk == sk_proc ) {
                iIdx = g_iLocalProcIdx;
                ++g_iLocalProcIdx;
            } else { // sk_var
                iIdx = g_iLocalVarIdx;
                ++g_iLocalVarIdx;
            }
        } else {
            if( IsLocal( symList ) ) {
                iIdx = g_iStackVarIdx;
                ++g_iStackVarIdx;
                if( sk == sk_var ) {
                    dwStorage = cSTORAGE_STACK;
                }
            } else {
                if( sk == sk_proc ) {
                    iIdx = g_iGlobalProcIdx;
                    ++g_iGlobalProcIdx;
                } else {
                    iIdx = g_iGlobalVarIdx;
                    ++g_iGlobalVarIdx;
                    dwStorage = cSTORAGE_DATA;
                }
            }
        }
    }// else it is not object in memory - set idx = 0;!

    //OutMsg( "AddSymbol: '%@', kind: %@, type: %@, idx: %@, flags: %@", csName, sk, dwType, iIdx, dwModFlags );
    Symbol PTR pSym NEW_OBJECT( Symbol );
    MEMBER_PTR(pSym)Init( sk, csName, dwType, iIdx, dwStorage, pParent, ADDROF(pOwner), dwModFlags );
    symList.push_front( pSym ); // no release, AddRef is done inside symList! 
    return DEREF(pSym);
}

// adds internal string variable into global scope
SymbolRef AddStringVarToGlobalScope( dword dwLitPoolIdx )
{
    string csName;
    csName.Format( "__str_%d", dwLitPoolIdx );
    SymbolRef Str = AddSymbol( g_listGlobal, sk_var, csName, t_string, NULL, getNULLSymbol(), f_const );
    Str.m_dwLiteralIdx = dwLitPoolIdx;
    return Str;
}

// need this because compiler uses pascall calling convention
void RevertArgIndexes( SYMBOLLIST symListArgs )
{
    int iIdx = -1;
    symListArgs.reset_to_begin();
    
    CONST symbolref PTR pArg = symListArgs.next();
    while( pArg ) {
        if( MEMBER_PTR( DEREF(pArg) )m_SymKind == sk_arg ) { // next go local variables
            MEMBER_PTR( DEREF(pArg) )m_iIndex = iIdx;
            --iIdx;
        }
        pArg = symListArgs.next();
    }
}

// helper function
STATIC void addFuncToComplexType( SymbolRef pArray, string fnName, dword dwRetType, dword argType, string argName )
{
    SymbolRef pMember = AddSymbol( pArray.m_listMembers, sk_proc, fnName, dwRetType, NULL, pArray, 0 );
    OpenLocalScope( pMember.m_listMembers, getNULLSymbol(), TRUE );
    AddSymbol( pMember.m_listMembers, sk_arg, argName, argType, NULL, getNULLSymbol(), 0 );
    pMember.m_dwArgumentsCount = 1;
}

void BuildArrayType( SYMBOLLIST symList, string csTypeName, SymbolRef pTemplateType )
{
    ResetLocalIdx();

    SymbolRef pArray = AddSymbol( symList, sk_typename, csTypeName, GenNewTypeCode(),  NULL, getNULLSymbol(), 0 );
    pArray.m_dwTemplSpecType = pTemplateType.m_dwType;
    OpenLocalScope( pArray.m_listMembers, getNULLSymbol(), TRUE );

    pArray.m_dwTemplateType = t_array;

    // 1. dword reserve( dword dwNumItems )
    SymbolRef pMember1 = AddSymbol( pArray.m_listMembers, sk_proc, "reserve", t_u4, NULL, pArray, 0 );
    OpenLocalScope( pMember1.m_listMembers, getNULLSymbol(), TRUE );
    AddSymbol( pMember1.m_listMembers, sk_arg, "dwNumItems", t_u4, NULL, getNULLSymbol(), 0 );
    pMember1.m_dwArgumentsCount = 1;

    // 2. dword allocated();
    SymbolRef pMember2 = AddSymbol( pArray.m_listMembers, sk_proc, "allocated", t_u4, NULL, pArray, 0 );
    OpenLocalScope( pMember2.m_listMembers, getNULLSymbol(), TRUE );
    pMember2.m_dwArgumentsCount = 0;

    // 3. dword add( const T& Item );
    SymbolRef pMember3 = AddSymbol( pArray.m_listMembers, sk_proc, "add", t_u4, NULL, pArray, 0 );
    OpenLocalScope( pMember3.m_listMembers, getNULLSymbol(), TRUE );
    AddSymbol( pMember3.m_listMembers, sk_arg, "Item", pTemplateType.m_dwType, NULL, getNULLSymbol(), 0 );
    pMember3.m_dwArgumentsCount = 1;

    // 4. dword del();
    SymbolRef pMember4 = AddSymbol( pArray.m_listMembers, sk_proc, "del", t_u4, NULL, pArray, 0 );
    OpenLocalScope( pMember4.m_listMembers, getNULLSymbol(), TRUE );
    pMember4.m_dwArgumentsCount = 0;

    // 5. void clear();
    SymbolRef pMember5 = AddSymbol( pArray.m_listMembers, sk_proc, "clear", t_void, NULL, pArray, 0 );
    OpenLocalScope( pMember5.m_listMembers, getNULLSymbol(), TRUE );
    pMember5.m_dwArgumentsCount = 0;

    // 6. void zero();
    SymbolRef pMember6 = AddSymbol( pArray.m_listMembers, sk_proc, "zero", t_void, NULL, pArray, 0 );
    OpenLocalScope( pMember6.m_listMembers, getNULLSymbol(), TRUE );
    pMember6.m_dwArgumentsCount = 0;

    // 7. dword put( dword idx, const T& Item );
    SymbolRef pMember7 = AddSymbol( pArray.m_listMembers, sk_proc, "put", t_u4, NULL, pArray, 0 );
    OpenLocalScope( pMember7.m_listMembers, getNULLSymbol(), TRUE );
    AddSymbol( pMember7.m_listMembers, sk_arg, "idx", t_u4, NULL, getNULLSymbol(), 0 );
    AddSymbol( pMember7.m_listMembers, sk_arg, "Item", pTemplateType.m_dwType, NULL, getNULLSymbol(), 0 );
    pMember7.m_dwArgumentsCount = 2;

    // 8. T& get( dword idx );
    SymbolRef pMember8 = AddSymbol( pArray.m_listMembers, sk_proc, "get", pTemplateType.m_dwType, NULL, pArray, 0 );
    OpenLocalScope( pMember8.m_listMembers, getNULLSymbol(), TRUE );
    AddSymbol( pMember8.m_listMembers, sk_arg, "idx", t_u4, NULL, getNULLSymbol(), 0 );
    pMember8.m_dwArgumentsCount = 1;

    // 9. dword count();
    SymbolRef pMember9 = AddSymbol( pArray.m_listMembers, sk_proc, "count", t_u4, NULL, pArray, 0 );
    OpenLocalScope( pMember9.m_listMembers, getNULLSymbol(), TRUE );
    pMember9.m_dwArgumentsCount = 0;

    // 10. dword copy( array ar );
    SymbolRef pMember10 = AddSymbol( pArray.m_listMembers, sk_proc, "copy", t_u4, NULL, pArray, 0 );
    OpenLocalScope( pMember10.m_listMembers, getNULLSymbol(), TRUE );
    AddSymbol( pMember10.m_listMembers, sk_arg, "Dst", pArray.m_dwType, NULL, getNULLSymbol(), 0 );
    pMember10.m_dwArgumentsCount = 1;

    if( pTemplateType.m_dwType == t_u1 || pTemplateType.m_dwType == t_s1 ) // byte array has extended functionality
    {
        addFuncToComplexType( pArray, "storeByte",  t_u4, t_u1, "Val" ); // 11 dword storeByte( byte b )
        addFuncToComplexType( pArray, "getByte",    t_u1, t_u4, "idx" ); // 12 byte getByte( dword dwAtIndex )
        addFuncToComplexType( pArray, "storeShort", t_u4, t_s2, "Val" ); // 13 dword storeShort( short s )
        addFuncToComplexType( pArray, "getShort",   t_s2, t_u4, "idx" ); // 14 short getShort( dword dwAtIndex )
        addFuncToComplexType( pArray, "storeWord",  t_u4, t_u2, "Val" ); // 15 dword storeWord( word w )
        addFuncToComplexType( pArray, "getWord",    t_u2, t_u4, "idx" ); // 16 word getWord( dword dwAtIndex )
        addFuncToComplexType( pArray, "storeInt",   t_u4, t_s4, "Val" ); // 17 dword storeInt( int i )
        addFuncToComplexType( pArray, "getInt",     t_s4, t_u4, "idx" ); // 18 int   getInt( dword dwAtIndex )
        addFuncToComplexType( pArray, "storeDword", t_u4, t_u4, "Val" ); // 19 dword storeDword( dword d )
        addFuncToComplexType( pArray, "getDword",   t_u4, t_u4, "idx" ); // 20 dword getDword( dword dwAtIndex )
        addFuncToComplexType( pArray, "storeLong",  t_u4, t_s8, "Val" ); // 21 dword storeLong( qlong l )
        addFuncToComplexType( pArray, "getLong",    t_s8, t_u4, "idx" ); // 22 qlong getLong( dword dwAtIndex )
        addFuncToComplexType( pArray, "storeQword", t_u4, t_u8, "Val" ); // 23 dword storeQword( qword q )
        addFuncToComplexType( pArray, "getQword",   t_u8, t_u4, "idx" ); // 24 qword getQword( dword dwAtIndex )
        addFuncToComplexType( pArray, "storeFloat", t_u4, t_r4, "Val" ); // 25 dword storeFloat( float f )
        addFuncToComplexType( pArray, "getFloat",   t_r4, t_u4, "idx" ); // 26 float getFloat( dword dwAtIndex )
        addFuncToComplexType( pArray, "storeDouble",t_u4, t_r8, "Val" ); // 27 dword storeDouble( double r )
        addFuncToComplexType( pArray, "getDouble",  t_r8, t_u4, "idx" ); // 28 double getDouble( dword dwAtIndex )
        addFuncToComplexType( pArray, "storePointer",t_u4, t_p, "Val" ); // 29 dword storePointer( xobject *p )
        addFuncToComplexType( pArray, "getPointer", t_p, t_u4, "idx" );  // 30 xobject* getPointer( dword dwAtIndex )
        addFuncToComplexType( pArray, "set_itemsCount", t_u4, t_u4, "Val" );  // 31 dword set_itemsCount( dword dwVal )

        pArray.m_dwFlags |= f_allowed_native; // mark this type as natively allowed
    }
}

// list should be reimplemented in the pure xort as soon as executive subsystem will be ready
//struct<typename T> ListIterator // defines the iterator
//{
//    T next();
//    T prev();
//    void reset_to_begin();
//    void reset_to_end();
//}
SymbolRef BuildListIterator( SYMBOLLIST symList, string csTypeName, SymbolRef pTemplateType )
{
    ResetLocalIdx();

    SymbolRef pListIter = AddSymbol( symList, sk_typename, csTypeName, GenNewTypeCode(),  NULL, getNULLSymbol(), 0 );
    pListIter.m_dwTemplSpecType = pTemplateType.m_dwType;
    OpenLocalScope( pListIter.m_listMembers, getNULLSymbol(), TRUE );

    pListIter.m_dwTemplateType = t_listiter;

    // 1 T next();
    SymbolRef pMember1 = AddSymbol( pListIter.m_listMembers, sk_proc, "next", pTemplateType.m_dwType, NULL, pListIter, 0 );
    OpenLocalScope( pMember1.m_listMembers, getNULLSymbol(), TRUE );
    pMember1.m_dwArgumentsCount = 0;

    // 2 T prev();
    SymbolRef pMember2 = AddSymbol( pListIter.m_listMembers, sk_proc, "prev", pTemplateType.m_dwType, NULL, pListIter, 0 );
    OpenLocalScope( pMember2.m_listMembers, getNULLSymbol(), TRUE );
    pMember2.m_dwArgumentsCount = 0;

    // 3 void reset_to_begin();
    SymbolRef pMember3 = AddSymbol( pListIter.m_listMembers, sk_proc, "reset_to_begin", t_void, NULL, pListIter, 0 );
    OpenLocalScope( pMember3.m_listMembers, getNULLSymbol(), TRUE );
    pMember3.m_dwArgumentsCount = 0;

    // 4 void reset_to_end();
    SymbolRef pMember4 = AddSymbol( pListIter.m_listMembers, sk_proc, "reset_to_end", t_void, NULL, pListIter, 0 );
    OpenLocalScope( pMember4.m_listMembers, getNULLSymbol(), TRUE );
    pMember4.m_dwArgumentsCount = 0;

    // 5 T item();
    SymbolRef pMember5 = AddSymbol( pListIter.m_listMembers, sk_proc, "item", pTemplateType.m_dwType, NULL, pListIter, 0 );
    OpenLocalScope( pMember5.m_listMembers, getNULLSymbol(), TRUE );
    pMember5.m_dwArgumentsCount = 0;

    return pListIter;
}

void BuildListType( SYMBOLLIST symList, string csTypeName, SymbolRef pTemplateType )
{
    // build list iterator for this type first
    string csIterTypeName;
    csIterTypeName.Assign( csTypeName );
    csIterTypeName.Add( "Iterator" );
    SymbolRef pListIter = BuildListIterator( symList, csIterTypeName, pTemplateType );

    ResetLocalIdx();

    SymbolRef pList = AddSymbol( symList, sk_typename, csTypeName, GenNewTypeCode(),  NULL, getNULLSymbol(), 0 );
    pList.m_dwTemplSpecType = pTemplateType.m_dwType;
    OpenLocalScope( pList.m_listMembers, getNULLSymbol(), TRUE );

    pList.m_dwTemplateType = t_list;

    // 1 void clear();
    SymbolRef pMember1 = AddSymbol( pList.m_listMembers, sk_proc, "clear", t_void, NULL, pList, 0 );
    OpenLocalScope( pMember1.m_listMembers, getNULLSymbol(), TRUE );
    pMember1.m_dwArgumentsCount = 0;

    // 2 dword push_front( const T& Item );
    SymbolRef pMember2 = AddSymbol( pList.m_listMembers, sk_proc, "push_front", t_u4, NULL, pList, 0 );
    OpenLocalScope( pMember2.m_listMembers, getNULLSymbol(), TRUE );
    AddSymbol( pMember2.m_listMembers, sk_arg, "Item", pTemplateType.m_dwType, NULL, getNULLSymbol(), 0 );
    pMember2.m_dwArgumentsCount = 1;

    // 3 dword push_back( const T& Item );
    SymbolRef pMember3 = AddSymbol( pList.m_listMembers, sk_proc, "push_back", t_u4, NULL, pList, 0 );
    OpenLocalScope( pMember3.m_listMembers, getNULLSymbol(), TRUE );
    AddSymbol( pMember3.m_listMembers, sk_arg, "Item", pTemplateType.m_dwType, NULL, getNULLSymbol(), 0 );
    pMember3.m_dwArgumentsCount = 1;

    // 4 dword pop_front();
    SymbolRef pMember4 = AddSymbol( pList.m_listMembers, sk_proc, "pop_front", t_u4, NULL, pList, 0 );
    OpenLocalScope( pMember4.m_listMembers, getNULLSymbol(), TRUE );
    pMember4.m_dwArgumentsCount = 0;

    // 5 dword pop_back();
    SymbolRef pMember5 = AddSymbol( pList.m_listMembers, sk_proc, "pop_back", t_u4, NULL, pList, 0 );
    OpenLocalScope( pMember5.m_listMembers, getNULLSymbol(), TRUE );
    pMember5.m_dwArgumentsCount = 0;

    // 6 dword size();
    SymbolRef pMember6 = AddSymbol( pList.m_listMembers, sk_proc, "size", t_u4, NULL, pList, 0 );
    OpenLocalScope( pMember6.m_listMembers, getNULLSymbol(), TRUE );
    pMember6.m_dwArgumentsCount = 0;

    // 7 void reset_to_begin();
    SymbolRef pMember7 = AddSymbol( pList.m_listMembers, sk_proc, "reset_to_begin", t_void, NULL, pList, 0 );
    OpenLocalScope( pMember7.m_listMembers, getNULLSymbol(), TRUE );
    pMember7.m_dwArgumentsCount = 0;

    // 8 const T* next();
    SymbolRef pMember8 = AddSymbol( pList.m_listMembers, sk_proc, "next", pTemplateType.m_dwType, NULL, pList, 0 );
    OpenLocalScope( pMember8.m_listMembers, getNULLSymbol(), TRUE );
    pMember8.m_dwArgumentsCount = 0;

    // 9 void reset_to_end();
    SymbolRef pMember9 = AddSymbol( pList.m_listMembers, sk_proc, "reset_to_end", t_void, NULL, pList, 0 );
    OpenLocalScope( pMember9.m_listMembers, getNULLSymbol(), TRUE );
    pMember9.m_dwArgumentsCount = 0;

    // 10 const T* prev();
    SymbolRef pMember10 = AddSymbol( pList.m_listMembers, sk_proc, "prev", pTemplateType.m_dwType, NULL, pList, 0 );
    OpenLocalScope( pMember10.m_listMembers, getNULLSymbol(), TRUE );
    pMember10.m_dwArgumentsCount = 0;

    // 11 dword copy( list Dst );
    SymbolRef pMember11 = AddSymbol( pList.m_listMembers, sk_proc, "copy", t_u4, NULL, pList, 0 );
    OpenLocalScope( pMember11.m_listMembers, getNULLSymbol(), TRUE );
    AddSymbol( pMember11.m_listMembers, sk_arg, "Dst", pList.m_dwType, NULL, getNULLSymbol(), 0 );
    pMember11.m_dwArgumentsCount = 1;

    // 12 ListIterator begin();
    SymbolRef pMember12 = AddSymbol( pList.m_listMembers, sk_proc, "begin", pListIter.m_dwType, NULL, pList, 0 );
    OpenLocalScope( pMember12.m_listMembers, getNULLSymbol(), TRUE );
    pMember12.m_dwArgumentsCount = 0;

    // 13 ListIterator end();
    SymbolRef pMember13 = AddSymbol( pList.m_listMembers, sk_proc, "end", pListIter.m_dwType, NULL, pList, 0 );
    OpenLocalScope( pMember13.m_listMembers, getNULLSymbol(), TRUE );
    pMember13.m_dwArgumentsCount = 0;

    // 14 ListIterator erase( ListIterator iter );
    SymbolRef pMember14 = AddSymbol( pList.m_listMembers, sk_proc, "erase", pListIter.m_dwType, NULL, pList, 0 );
    OpenLocalScope( pMember14.m_listMembers, getNULLSymbol(), TRUE );
    AddSymbol( pMember14.m_listMembers, sk_arg, "iter", pListIter.m_dwType, NULL, getNULLSymbol(), 0 );
    pMember14.m_dwArgumentsCount = 1;
}

void BuildComplexType( SYMBOLLIST symList, string csName, dword dwBuildInTypeCode, SymbolRef pTemplateType )
{
    if( dwBuildInTypeCode == tk_array ) {
        BuildArrayType( symList, csName, pTemplateType );
    } else if( dwBuildInTypeCode == tk_list ) {
        BuildListType( symList, csName, pTemplateType );
    } else {
        Token Tok = lex_GetLastToken();
        x_error( ERR_INTERNAL_COMPILER, Tok.m_dwLine, Tok.m_dwPos );
        message( "BuildComplexType() -> unknown typecode passed" );
    }
}

void BuildStringType( SYMBOLLIST symList )
{
    ResetLocalIdx();

    SymbolRef pStr = AddSymbol( symList, sk_typename, "string", t_string,  NULL, getNULLSymbol(), f_allowed_native );
    OpenLocalScope( pStr.m_listMembers, getNULLSymbol(), TRUE );

    // 1 dword Assign ( string csLiteral ); - returns the new length of string, or 0 in case of failure
    SymbolRef pMember1 = AddSymbol( pStr.m_listMembers, sk_proc, "Assign", t_u4, NULL, pStr, 0 );
    OpenLocalScope( pMember1.m_listMembers, getNULLSymbol(), TRUE );
    AddSymbol( pMember1.m_listMembers, sk_arg, "csLiteral", t_string, NULL, getNULLSymbol(), 0 );
    pMember1.m_dwArgumentsCount = 1;

    // 2 dword Add ( string csLiteral );
    SymbolRef pMember2 = AddSymbol( pStr.m_listMembers, sk_proc, "Add", t_u4, NULL, pStr, 0 );
    OpenLocalScope( pMember2.m_listMembers, getNULLSymbol(), TRUE );
    AddSymbol( pMember2.m_listMembers, sk_arg, "csLiteral", t_string, NULL, getNULLSymbol(), 0 );
    pMember2.m_dwArgumentsCount = 1;

    // 3 dword Append( byte ch );
    SymbolRef pMember3 = AddSymbol( pStr.m_listMembers, sk_proc, "Append", t_u4, NULL, pStr, 0 );
    OpenLocalScope( pMember3.m_listMembers, getNULLSymbol(), TRUE );
    AddSymbol( pMember3.m_listMembers, sk_arg, "ch", t_u1, NULL, getNULLSymbol(), 0 );
    pMember3.m_dwArgumentsCount = 1;

    // 4 byte   CharAt( dword dwPos );
    SymbolRef pMember4 = AddSymbol( pStr.m_listMembers, sk_proc, "CharAt", t_u1, NULL, pStr, 0 );
    OpenLocalScope( pMember4.m_listMembers, getNULLSymbol(), TRUE );
    AddSymbol( pMember4.m_listMembers, sk_arg, "dwPos", t_u4, NULL, getNULLSymbol(), 0 );
    pMember4.m_dwArgumentsCount = 1;

    // 5 dword  Length();
    SymbolRef pMember5 = AddSymbol( pStr.m_listMembers, sk_proc, "Length", t_u4, NULL, pStr, 0 );
    OpenLocalScope( pMember5.m_listMembers, getNULLSymbol(), TRUE );
    pMember5.m_dwArgumentsCount = 0;

    // 6 void   Empty();
    SymbolRef pMember6 = AddSymbol( pStr.m_listMembers, sk_proc, "Empty", t_void, NULL, pStr, 0 );
    OpenLocalScope( pMember6.m_listMembers, getNULLSymbol(), TRUE );
    pMember6.m_dwArgumentsCount = 0;

    // 7 int Compare( string cs );
    SymbolRef pMember7 = AddSymbol( pStr.m_listMembers, sk_proc, "Compare", t_s4, NULL, pStr, 0 );
    OpenLocalScope( pMember7.m_listMembers, getNULLSymbol(), TRUE );
    AddSymbol( pMember7.m_listMembers, sk_arg, "csLiteral", t_string, NULL, getNULLSymbol(), 0 );
    pMember7.m_dwArgumentsCount = 1;

    // 8 double doubleValue();
    SymbolRef pMember8 = AddSymbol( pStr.m_listMembers, sk_proc, "doubleValue", t_r8, NULL, pStr, 0 );
    OpenLocalScope( pMember8.m_listMembers, getNULLSymbol(), TRUE );
    pMember8.m_dwArgumentsCount = 0;

    // 9 float  floatValue();
    SymbolRef pMember9 = AddSymbol( pStr.m_listMembers, sk_proc, "floatValue", t_r4, NULL, pStr, 0 );
    OpenLocalScope( pMember9.m_listMembers, getNULLSymbol(), TRUE );
    pMember9.m_dwArgumentsCount = 0;

    // 10 int    intValue();
    SymbolRef pMember10 = AddSymbol( pStr.m_listMembers, sk_proc, "intValue", t_s4, NULL, pStr, 0 );
    OpenLocalScope( pMember10.m_listMembers, getNULLSymbol(), TRUE );
    pMember10.m_dwArgumentsCount = 0;

    // 11 qlong  longValue();
    SymbolRef pMember11 = AddSymbol( pStr.m_listMembers, sk_proc, "longValue", t_s8, NULL, pStr, 0 );
    OpenLocalScope( pMember11.m_listMembers, getNULLSymbol(), TRUE );
    pMember11.m_dwArgumentsCount = 0;

    // 12 void Format( string csFmt, ... ); this is very specific function - gets the unspecified number of args!
    // csFmt expected to be like the following: "wrqwer %@ qrwerq %@" etc...
    SymbolRef pMember12 = AddSymbol( pStr.m_listMembers, sk_proc, "Format", t_u1, NULL, pStr, f_unspecnumargs );
    OpenLocalScope( pMember12.m_listMembers, getNULLSymbol(), TRUE );
    AddSymbol( pMember12.m_listMembers, sk_arg, "csFmt", t_string, NULL, getNULLSymbol(), 0 );
    AddSymbol( pMember12.m_listMembers, sk_arg, "$", t_void, NULL, getNULLSymbol(), 0 ); // indicates the multiple arguments followed!
    pMember12.m_dwArgumentsCount = 0xFFFFFFFF;

    // 13 dword Replace( string strOld, string strNew );
    SymbolRef pMember13 = AddSymbol( pStr.m_listMembers, sk_proc, "Replace", t_u4, NULL, pStr, 0 );
    OpenLocalScope( pMember13.m_listMembers, getNULLSymbol(), TRUE );
    AddSymbol( pMember13.m_listMembers, sk_arg, "csOld", t_string, NULL, getNULLSymbol(), 0 );
    AddSymbol( pMember13.m_listMembers, sk_arg, "csNew", t_string, NULL, getNULLSymbol(), 0 );
    AddSymbol( pMember13.m_listMembers, sk_arg, "dwNumRepl", t_u4, NULL, getNULLSymbol(), 0 );
    pMember13.m_dwArgumentsCount = 3;

    // 14 dword hasChr( byte ch )
    SymbolRef pMember14 = AddSymbol( pStr.m_listMembers, sk_proc, "hasChr", t_u4, NULL, pStr, 0 );
    OpenLocalScope( pMember14.m_listMembers, getNULLSymbol(), TRUE );
    AddSymbol( pMember14.m_listMembers, sk_arg, "ch", t_u1, NULL, getNULLSymbol(), 0 );
    pMember14.m_dwArgumentsCount = 1;

    // 15 void dword2Str( dword d );
    SymbolRef pMember15 = AddSymbol( pStr.m_listMembers, sk_proc, "dword2Str", t_v, NULL, pStr, 0 );
    OpenLocalScope( pMember15.m_listMembers, getNULLSymbol(), TRUE );
    AddSymbol( pMember15.m_listMembers, sk_arg, "dw", t_u4, NULL, getNULLSymbol(), 0 );
    pMember15.m_dwArgumentsCount = 1;

    // 16 int ReverseFind( byte ch );
    SymbolRef pMember16 = AddSymbol( pStr.m_listMembers, sk_proc, "ReverseFind", t_s4, NULL, pStr, 0 );
    OpenLocalScope( pMember16.m_listMembers, getNULLSymbol(), TRUE );
    AddSymbol( pMember16.m_listMembers, sk_arg, "ch", t_u1, NULL, getNULLSymbol(), 0 );
    pMember16.m_dwArgumentsCount = 1;

    // 17 void Truncate( dword dwStartPos );
    SymbolRef pMember17 = AddSymbol( pStr.m_listMembers, sk_proc, "Truncate", t_v, NULL, pStr, 0 );
    OpenLocalScope( pMember17.m_listMembers, getNULLSymbol(), TRUE );
    AddSymbol( pMember17.m_listMembers, sk_arg, "dwStartPos", t_u4, NULL, getNULLSymbol(), 0 );
    pMember17.m_dwArgumentsCount = 1;

    // 18 int IsEmpty();
    SymbolRef pMember18 = AddSymbol( pStr.m_listMembers, sk_proc, "IsEmpty", t_s4, NULL, pStr, 0 );
    OpenLocalScope( pMember18.m_listMembers, getNULLSymbol(), TRUE );
    pMember18.m_dwArgumentsCount = 0;

    // 19 string Substring( int iStartPos );
    SymbolRef pMember19 = AddSymbol( pStr.m_listMembers, sk_proc, "Substring", t_string, NULL, pStr, 0 );
    OpenLocalScope( pMember19.m_listMembers, getNULLSymbol(), TRUE );
    AddSymbol( pMember19.m_listMembers, sk_arg, "iStartPos", t_s4, NULL, getNULLSymbol(), 0 );
    pMember19.m_dwArgumentsCount = 1;
}

void BuildXortElementType( SYMBOLLIST symList ) 
{
    ResetLocalIdx();

    SymbolRef pArg = AddSymbol( symList, sk_typename, "XortElement", t_xelement,  NULL, getNULLSymbol(), 0 );
    OpenLocalScope( pArg.m_listMembers, getNULLSymbol(), TRUE );

    // byte bType;
    SymbolRef pMember1 = AddSymbol( pArg.m_listMembers, sk_var, "bType", t_u1, NULL, pArg, 0 );
    // byte bAccess;
    SymbolRef pMember2 = AddSymbol( pArg.m_listMembers, sk_var, "bAccess", t_u1, NULL, pArg, 0 );
    // char    _s1;
    SymbolRef pMember3 = AddSymbol( pArg.m_listMembers, sk_var, "_s1", t_s1, NULL, pArg, 0 );
    // byte    _u1;
    SymbolRef pMember4 = AddSymbol( pArg.m_listMembers, sk_var, "_u1", t_u1, NULL, pArg, 0 );
    // short   _s2;
    SymbolRef pMember5 = AddSymbol( pArg.m_listMembers, sk_var, "_s2", t_s2, NULL, pArg, 0 );
    // word    _u2;
    SymbolRef pMember6 = AddSymbol( pArg.m_listMembers, sk_var, "_u2", t_u2, NULL, pArg, 0 );
    // int     _s4;
    SymbolRef pMember7 = AddSymbol( pArg.m_listMembers, sk_var, "_s4", t_s4, NULL, pArg, 0 );
    // dword   _u4;
    SymbolRef pMember8 = AddSymbol( pArg.m_listMembers, sk_var, "_u4", t_u4, NULL, pArg, 0 );
    // qlong   _s8;
    SymbolRef pMember9 = AddSymbol( pArg.m_listMembers, sk_var, "_s8", t_s8, NULL, pArg, 0 );
    // qword   _u8;
    SymbolRef pMember10 = AddSymbol( pArg.m_listMembers, sk_var, "_u8", t_u8, NULL, pArg, 0 );
    // float   _r4;
    SymbolRef pMember11 = AddSymbol( pArg.m_listMembers, sk_var, "_r4", t_r4, NULL, pArg, 0 );
    // real    _r8;
    SymbolRef pMember12 = AddSymbol( pArg.m_listMembers, sk_var, "_r8", t_r8, NULL, pArg, 0 );
    // IXObject _p;
    SymbolRef pMember13 = AddSymbol( pArg.m_listMembers, sk_var, "_p", t_p, NULL, pArg, 0 );
    // void Clear();
    SymbolRef pMember14 = AddSymbol( pArg.m_listMembers, sk_proc, "Clear", t_v, NULL, pArg, 0 );
    OpenLocalScope( pMember14.m_listMembers, getNULLSymbol(), TRUE );
    pMember14.m_dwArgumentsCount = 0;
    // void SetValue( XortElement vVal );
    SymbolRef pMember15 = AddSymbol( pArg.m_listMembers, sk_proc, "SetValue", t_v, NULL, pArg, 0 );
    OpenLocalScope( pMember15.m_listMembers, getNULLSymbol(), TRUE );
    AddSymbol( pMember15.m_listMembers, sk_arg, "vValue", t_xelement, NULL, getNULLSymbol(), 0 );
    pMember15.m_dwArgumentsCount = 1;

    //BuildArrayType( symList, "__XELEMENTARRAY", pArg ); // typedef array<XortElement> __XELEMENTARRAY;
}

// add build-in symbols
void InitSymbolTable( SYMBOLLIST symList )
{
    g_NULLSymbol.Init( sk_nullsymbol, "NULLSYMBOL", 0, 0, 0, NULL, NULL, 0 );
    AddSymbol( symList, sk_scopeglobal, "@__global", t_void,    NULL, getNULLSymbol(), 0 );
    AddSymbol( symList, sk_typename, "char",         t_s1,      NULL, getNULLSymbol(), f_allowed_native );
    AddSymbol( symList, sk_typename, "byte",         t_u1,      NULL, getNULLSymbol(), f_allowed_native );
    AddSymbol( symList, sk_typename, "short",        t_s2,      NULL, getNULLSymbol(), f_allowed_native );
    AddSymbol( symList, sk_typename, "word",         t_u2,      NULL, getNULLSymbol(), f_allowed_native );
    AddSymbol( symList, sk_typename, "int",          t_s4,      NULL, getNULLSymbol(), f_allowed_native );
    AddSymbol( symList, sk_typename, "dword",        t_u4,      NULL, getNULLSymbol(), f_allowed_native );
    AddSymbol( symList, sk_typename, "long",         t_s8,      NULL, getNULLSymbol(), f_allowed_native );
    AddSymbol( symList, sk_typename, "qword",        t_u8,      NULL, getNULLSymbol(), f_allowed_native );
    AddSymbol( symList, sk_typename, "float",        t_r4,      NULL, getNULLSymbol(), f_allowed_native );
    AddSymbol( symList, sk_typename, "double",       t_r8,      NULL, getNULLSymbol(), f_allowed_native );
    AddSymbol( symList, sk_typename, "void",         t_void,    NULL, getNULLSymbol(), f_allowed_native );

    SymbolRef dbgPrintProc = AddSymbol( symList, sk_proc, "DbgPrint", t_void, NULL, getNULLSymbol(), f_unspecnumargs | f_buildinfunc );
    OpenLocalScope( dbgPrintProc.m_listMembers, getNULLSymbol(), TRUE );
    AddSymbol( dbgPrintProc.m_listMembers, sk_arg, "csFmt", t_string, NULL, getNULLSymbol(), 0 );
    AddSymbol( dbgPrintProc.m_listMembers, sk_arg, "$", t_void, NULL, getNULLSymbol(), 0 );
    dbgPrintProc.m_dwArgumentsCount = 0xFFFFFFFF;

    BuildStringType( symList );

    BuildXortElementType( symList ); // XortElement;

    // unspecified number of arguments support
    // dword __get_arg_count();
    SymbolRef getArgCountProc = AddSymbol( symList, sk_proc, "__get_arg_count", t_u4, NULL, getNULLSymbol(), f_buildinfunc );
    OpenLocalScope( getArgCountProc.m_listMembers, getNULLSymbol(), TRUE );
    getArgCountProc.m_dwArgumentsCount = 0;

    // XortElement __get_arg( dword idx );
    SymbolRef getArgProc = AddSymbol( symList, sk_proc, "__get_arg", t_xelement, NULL, getNULLSymbol(), f_buildinfunc );
    OpenLocalScope( getArgProc.m_listMembers, getNULLSymbol(), TRUE );
    AddSymbol( getArgProc.m_listMembers, sk_arg, "idx", t_u4, NULL, getNULLSymbol(), 0 );
    getArgProc.m_dwArgumentsCount = 1;
}

void ClearSymbolTable( SYMBOLLIST symList )
{
    symList.reset_to_end();

    CONST symbolref PTR Sym = symList.prev();
    while( Sym )
    {
        ClearSymbolTable( MEMBER_PTR( DEREF( Sym ) )m_listMembers );

        MEMBER_PTR( DEREF( Sym ) )Zero();

        Sym = symList.prev();
    }

    symList.clear();
}

// opens the local scope for function
void OpenLocalScope( SYMBOLLIST symList, SymbolRef Proc, int bResetArgIdx )
{
    Symbol PTR Sym NEW_OBJECT(Symbol);

    MEMBER_PTR(Sym)Init( sk_scopelocal, cLOCAL_MARKER, t_void, 0, 0, NULL, ADDROF(Proc), 0 );

    symList.push_front( Sym );

    if( !Proc.isNULL() && Proc.m_SymKind == sk_proc )
    {
        symbolref pSymLeave NEW_OBJECT(Symbol); // it is not an error, YES, I add FRAME_LEAVE marker in to open scope, and ENTER in the close scope.
        MEMBER_PTR(pSymLeave)Init( sk_scopelocal, cFRAME_LEAVE, t_void, 0, 0, NULL, NULL, 0 ); // This is intendedly done, because they are going in the reverse order!
        Proc.m_stackMembers.push_front( pSymLeave );
    }

    if( bResetArgIdx )
        ResetArgIdx();
}

// closes the local scope for function - this will actually delete all information about local variables 
// ... but it can be used for debugger ... :(
void CloseLocalScope( SYMBOLLIST symList, SymbolRef Proc )
{
    symList.reset_to_begin();

    CONST symbolref PTR pSym = symList.next();
    while( pSym && ( MEMBER_PTR((DEREF(pSym)))m_SymKind != sk_scopelocal ) ) {
        MEMBER_PTR( DEREF( pSym ) )m_pParent = NULL; // fix cross references
        MEMBER_PTR( DEREF( pSym ) )m_pOwner = NULL;
        Proc.m_stackMembers.push_front( DEREF(pSym) ); // save local symbol information for debugger
        pSym = symList.next();
        symList.pop_front();
    }
    if( pSym && MEMBER_PTR((DEREF(pSym)))m_SymKind == sk_scopelocal ) {// finally delete scope marker
        symList.pop_front();
    }

    Symbol PTR pSymLeave NEW_OBJECT(Symbol);
    MEMBER_PTR(pSymLeave)Init( sk_scopelocal, cFRAME_ENTER, t_void, 0, 0, NULL, NULL, 0 ); // generate instruction for debugger to leave this frame
    Proc.m_stackMembers.push_front( pSymLeave ); 
}

void SaveString( string str, FileRef pFile )
{
    dword dwLen = str.Length();
    pFile.WriteDword( dwLen );
    pFile.WriteString( str );
}

string LoadString( FileRef pFile )
{
    dword dwLen = pFile.ReadDword();
    return pFile.ReadString( dwLen );
}

void SaveStringArray( STRINGARRAY ar, FileRef pFile )
{
    dword i;
    dword dwCount = ar.count();

    pFile.WriteDword( dwCount );

    for( i = 0; i < dwCount; ++i )
    {
        string str = DEREF( (ar.get( i )) );
        SaveString( str, pFile );
    }
}

void LoadStringArray( FileRef pFile, STRINGARRAY ar )
{
    dword i;
    dword dwCount = pFile.ReadDword();

    for( i = 0; i < dwCount; ++i )
    {
        string str = LoadString( pFile );
#ifdef CPP_COMPILER
        stringref p = new_string;
#else
        string p;
#endif
        MEMBER_PTR(p)Assign( str );
        ar.add( p );
#ifdef __XVM__
        p->Release();
#endif
    }
}

STATIC void SaveXortElement( XELEMENT Value, FileRef pFile )
{
    byte bType = Value.bType;
    pFile.WriteByte( bType );
    switch( bType )
    {
    case t_v:   break;
    case t_s1: pFile.WriteByte( Value._s1 ); break;
    case t_u1: pFile.WriteByte( Value._u1 ); break;
    case t_s2: pFile.WriteWord( Value._s2 ); break;
    case t_u2: pFile.WriteWord( Value._u2 ); break;
    case t_s4: pFile.WriteDword( Value._s4 ); break;
    case t_u4: pFile.WriteDword( Value._u4 ); break;
    case t_s8: pFile.WriteQword( Value._s8 ); break;
    case t_u8: pFile.WriteQword( Value._u8 ); break;
    case t_r4: pFile.WriteDword( Value._u4 ); break;
    case t_r8: pFile.WriteQword( Value._u8 ); break;
    case t_p : pFile.WriteDword( 0 ); break;
    default:
        message( "INTERNAL COMPILER ERROR -> SaveXortElement - unknown type!" );
        break;
    }
}

STATIC void LoadXortElement( XELEMENT Value, FileRef pFile )
{
    Value.Clear();
    Value.bType = pFile.ReadByte();
    switch( Value.bType )
    {
    case t_v:  Value.bType = t_v; break;
    case t_s1: Value._s1 = pFile.ReadByte(); break;
    case t_u1: Value._u1 = pFile.ReadByte(); break;
    case t_s2: Value._s2 = pFile.ReadWord(); break;
    case t_u2: Value._u2 = pFile.ReadWord(); break;
    case t_s4: Value._s4 = pFile.ReadDword(); break;
    case t_u4: Value._u4 = pFile.ReadDword(); break;
    case t_s8: Value._s8 = pFile.ReadQword(); break;
    case t_u8: Value._u8 = pFile.ReadQword(); break;
    case t_r4: Value._u4 = pFile.ReadDword(); break;
    case t_r8: Value._u8 = pFile.ReadQword(); break;
    case t_p : Value._p = NULL; pFile.ReadDword(); break;
    default:
        message( "INTERNAL COMPILER ERROR -> LoadXortElement - unknown type!" );
        break;
    }
}

STATIC void SaveCode( SymbolRef Sym, FileRef pFile )
{
    dword dwSize = Sym.m_Code.count();
    pFile.WriteDword( dwSize );
    
    if( dwSize )
    {
        dword i;
        for( i = 0; i < dwSize; ++i )
        {
            InstructionData PTR instrData = Sym.getInstructionByIndex( i );
            pFile.WriteDword( MEMBER_PTR(instrData)m_dwLineNumber );
            pFile.WriteByte( MEMBER_PTR(instrData)m_bInstrCode );
            pFile.WriteByte( MEMBER_PTR(instrData)m_bTypeAddr );
            SaveXortElement( MEMBER_PTR(instrData)m_Value, pFile );
            SaveXortElement( MEMBER_PTR(instrData)m_Value2, pFile );
        }
    }
}

STATIC void LoadCode( Symbol PTR Sym, FileRef pFile )
{
    dword dwSize = pFile.ReadDword();
    
    if( dwSize )
    {
        dword i;
        for( i = 0; i < dwSize; ++i )
        {
            InstructionData PTR instrData NEW_OBJECT(InstructionData);
            MEMBER_PTR(instrData)m_dwLineNumber = pFile.ReadDword();
            MEMBER_PTR(instrData)m_bInstrCode = pFile.ReadByte();
            MEMBER_PTR(instrData)m_bTypeAddr = pFile.ReadByte();
            LoadXortElement( MEMBER_PTR(instrData)m_Value, pFile );
            LoadXortElement( MEMBER_PTR(instrData)m_Value2, pFile );

            MEMBER_PTR(Sym)addInstruction( instrData );
        }
    }
}

STATIC void SaveSymbol( SymbolRef Sym, FileRef pFile )
{
    dword dwSize;
    pFile.WriteDword( Sym.m_SymKind );
    SaveString( Sym.m_csName, pFile );
    SaveStringArray( Sym.m_arAliasNames, pFile );
    pFile.WriteDword( Sym.m_dwType );
    pFile.WriteDword( Sym.m_dwTemplateType );
    pFile.WriteDword( Sym.m_dwTemplSpecType );
    pFile.WriteDword( Sym.m_dwFlags );
    
    //Sym.m_pParent; // ignore this member

    SaveCode( Sym, pFile );

    pFile.WriteByte( Sym.m_Value.bType );
    pFile.WriteByte( Sym.m_Value.bAccess );
    pFile.WriteQword( Sym.m_Value._u8 );
    pFile.WriteDword( Sym.m_dwLiteralIdx );
    pFile.WriteInt( Sym.m_iIndex );
    pFile.WriteDword( Sym.m_dwStorage );

    // save local variables or object members
    dwSize = Sym.m_listMembers.size();
    pFile.WriteDword( dwSize );
    if( dwSize )
    {
        SaveSymbolTable( Sym.m_listMembers, pFile );
    }

    // save stack transition for debugger
    dwSize = Sym.m_stackMembers.size();
    pFile.WriteDword( dwSize );
    if( dwSize )
    {
        SaveSymbolTable( Sym.m_stackMembers, pFile );
    }

    // save attributes if any
    dwSize = Sym.m_arAttributes.count();
    pFile.WriteDword( dwSize );
    if( dwSize ) {
        dword i;
        for( i = 0; i < dwSize; ++i ) {
            AttributesRef attr = Sym.m_arAttributes.get( i );
            pFile.WriteDword( MEMBER_PTR(attr)dwAttrCode );
            SaveString( MEMBER_PTR(attr)csAttrValue, pFile );
        }
    }
}

void SaveSymbolTable( SYMBOLLIST symList, FileRef pFile )
{
    symList.reset_to_end();
    CONST symbolref PTR pSym = symList.prev();
    while( pSym ) {
        SaveSymbol( DEREF(DEREF(pSym)), pFile );
        pSym = symList.prev();
    }
}

int GenExecutable( SYMBOLLIST symList, string csFileName )
{
    File exe; 
    if( exe.Open( csFileName, "wb" ) )
    {
        dword i;
        dword dwIgnored = 0;
        dword dwVal = 1.0;
        string csSignature = "XORT";

        exe.WriteString( csSignature );
        exe.WriteDword( dwVal );
        exe.WriteDword( dwIgnored ); // UTC time
        exe.WriteDword( dwIgnored ); // Data size
        exe.WriteDword( dwIgnored ); // Data offset
        exe.WriteDword( dwIgnored ); // Code size
        exe.WriteDword( dwIgnored ); // Code offset
        exe.WriteDword( dwIgnored ); // MData size
        exe.WriteDword( dwIgnored ); // MData offset
        exe.WriteDword( dwIgnored ); // Entry point proc - index
        exe.WriteDword( dwIgnored ); // Arith stack size
        exe.WriteDword( dwIgnored ); // Ret stack size
        exe.WriteDword( dwIgnored ); // Check summ
        exe.WriteDword( dwIgnored ); // pwd MD5
        exe.WriteDword( dwIgnored ); // pwd MD5
        exe.WriteDword( dwIgnored ); // pwd MD5
        exe.WriteDword( dwIgnored ); // pwd MD5
 
        for( i = 0; i < 15; ++i ) {
            exe.WriteDword( dwIgnored ); // reserved
        }

        csSignature = "MTDA";
        exe.WriteString( csSignature );
        dwVal = symList.size();
        exe.WriteDword( dwVal ); // size of global link
        SaveSymbolTable( symList, exe );

        SaveLiteralPool( exe );
        
        exe.Close();
        return XORT_OK;
    }

    return 0;
}

//////////////////////////////////////////////////////////////////////////
// this stuff belongs to disassembler
void LoadLiteralPool( FileRef pFile, STRINGARRAY litPool )
{
    dword i = 0;
    dword dwSize = g_arLiterals.count();

    string str = pFile.ReadString( 4 );
    if( str.Compare( "LITP" ) == 0 )
    {
        dwSize = pFile.ReadDword();

        while( i < dwSize ) {
            dword dwLen = pFile.ReadDword();
            str = pFile.ReadString( dwLen );
#ifdef CPP_COMPILER
            stringref s = new_string;
#else
            string s;
#endif
            MEMBER_PTR(s)Assign( str );
            litPool.add( s );
            ++i;
#ifdef __XVM__
            s->Release();
#endif 
        }
    }
}

STATIC void LoadSymbolTable( FileRef pFile, SYMBOLLIST symList, Symbol PTR Owner, dword dwMainLinkSize );

symbolref LoadSymbol( FileRef pFile, Symbol PTR Owner )
{
    Symbol PTR Sym NEW_OBJECT(Symbol);
    MEMBER_PTR(Sym)Zero();

    MEMBER_PTR(Sym)m_pOwner = Owner;
    
    dword dwSize;
    MEMBER_PTR(Sym)m_SymKind = pFile.ReadDword();
    MEMBER_PTR(Sym)m_csName = LoadString( pFile );
    LoadStringArray( pFile, MEMBER_PTR(Sym)m_arAliasNames );
    MEMBER_PTR(Sym)m_dwType = pFile.ReadDword();
    MEMBER_PTR(Sym)m_dwTemplateType = pFile.ReadDword();
    MEMBER_PTR(Sym)m_dwTemplSpecType = pFile.ReadDword();
    MEMBER_PTR(Sym)m_dwFlags = pFile.ReadDword();

    //MEMBER_PTR(Sym)m_pParent; // ignore this member

    LoadCode( Sym, pFile );

    MEMBER_PTR(Sym)m_Value.bType = pFile.ReadByte();
    MEMBER_PTR(Sym)m_Value.bAccess = pFile.ReadByte();
    MEMBER_PTR(Sym)m_Value._u8 = pFile.ReadQword();
    MEMBER_PTR(Sym)m_dwLiteralIdx = pFile.ReadDword();
    MEMBER_PTR(Sym)m_iIndex = pFile.ReadInt();
    MEMBER_PTR(Sym)m_dwStorage = pFile.ReadDword();

    dwSize = pFile.ReadDword();
    if( dwSize ) // list members
    {
        LoadSymbolTable( pFile, MEMBER_PTR(Sym)m_listMembers, Sym, dwSize );
    }

    // for procedures update the number of arguments:
    if( MEMBER_PTR(Sym)m_SymKind == sk_proc )
        MEMBER_PTR(Sym)m_dwArgumentsCount = MEMBER_PTR(Sym)m_listMembers.size() - 1;

    dwSize = pFile.ReadDword();
    if( dwSize ) // stack transitions
    {
        LoadSymbolTable( pFile, MEMBER_PTR(Sym)m_stackMembers, Sym, dwSize );
    }

    // load attributes if any
    dwSize = pFile.ReadDword();
    if( dwSize ) {
        dword i;
        for( i = 0; i < dwSize; ++i ) {
            AttributesRef attr NEW_OBJECT(Attributes);
            MEMBER_PTR(attr)dwAttrCode = pFile.ReadDword();
            MEMBER_PTR(attr)csAttrValue = LoadString( pFile );
            MEMBER_PTR(Sym)m_arAttributes.add( attr );
        }
    }

    return Sym;
}


STATIC void LoadSymbolTable( FileRef pFile, SYMBOLLIST symList, Symbol PTR Owner, dword dwMainLinkSize )
{
    dword i;
    for( i = 0; i < dwMainLinkSize; ++i )
    {
        symbolref pSym = LoadSymbol( pFile, Owner );
        symList.push_front( pSym );
    }
}

int LoadExecutable( string csFileName, SYMBOLLIST symList, STRINGARRAY litPool )
{
    File exe;
    if( exe.Open( csFileName, "rb" ) )
    {
        string csSignature = exe.ReadString( 4 );
        if( csSignature.Compare( "XORT" ) == 0 )
        {
            dword dwIgnored;
            dword dwVal = exe.ReadDword();
            dwIgnored = exe.ReadDword(); // UTC time
            dwIgnored = exe.ReadDword(); // Data size
            dwIgnored = exe.ReadDword(); // Data offset
            dwIgnored = exe.ReadDword(); // Code size
            dwIgnored = exe.ReadDword(); // Code offset
            dwIgnored = exe.ReadDword(); // MData size
            dwIgnored = exe.ReadDword(); // MData offset
            dwIgnored = exe.ReadDword(); // Entry point proc - index
            dwIgnored = exe.ReadDword(); // Arith stack size
            dwIgnored = exe.ReadDword(); // Ret stack size
            dwIgnored = exe.ReadDword(); // Check summ
            dwIgnored = exe.ReadDword(); // pwd MD5
            dwIgnored = exe.ReadDword(); // pwd MD5
            dwIgnored = exe.ReadDword(); // pwd MD5
            dwIgnored = exe.ReadDword(); // pwd MD5

            dword i;
            for( i = 0; i < 15; ++i ) {
                exe.ReadDword(); // reserved
            }

            csSignature = exe.ReadString( 4 );
            if( csSignature.Compare( "MTDA" ) == 0 )
            {
                dwVal = exe.ReadDword(); // size of global link
                LoadSymbolTable( exe, symList, NULL, dwVal );
            }

            LoadLiteralPool( exe, litPool );
        }

        exe.Close();
        return XORT_OK;
    }

    return 0;
}

void GetSymbolListInfo( SYMBOLLIST symList, SymbolListInfoRef symListInfo )
{
    symListInfo.dwTotalSymbolsCount = 0;
    symListInfo.dwFunctionsCount    = 0;
    symListInfo.dwVariblesCount     = 0;

#ifdef CPP_COMPILER
    SYMBOL_LIST::iterator theIter = symList.begin();
    symbolref pSym = (Symbol*)theIter;
#else
    SYMBOL_LISTIterator theIter = symList.begin();
    Symbol pSym = theIter.next();
#endif
    while( pSym )
    {
        if( MEMBER_PTR(pSym)m_SymKind == sk_var )
        {
            symListInfo.dwVariblesCount += 1;
        }
        else if( MEMBER_PTR(pSym)m_SymKind == sk_proc )
        {
            symListInfo.dwFunctionsCount += 1;
        }

        symListInfo.dwTotalSymbolsCount += 1;

#ifdef CPP_COMPILER
        theIter++;
        pSym = ( theIter == NULL ) ? NULL : (Symbol*)theIter;
#else
        pSym = theIter.next();
#endif
    }
}

STATIC void RemoveStkTarnsition( SYMBOLLIST symList )
{
#ifdef CPP_COMPILER
    SYMBOL_LIST::iterator theIter2, theIter1 = symList.begin();
    symbolref pSym = (Symbol*)theIter1;
    symbolref pSym2;

    while( pSym )
    {
        if( MEMBER_PTR(pSym)m_csName.Compare(cFRAME_ENTER) == 0 )
        {
            theIter2 = theIter1;
            theIter1++;
            pSym2 = (theIter1 == NULL) ? NULL : (Symbol*)theIter1;

            if( pSym2 && (MEMBER_PTR(pSym2)m_csName.Compare(cFRAME_LEAVE) == 0) )
            {
                theIter1 = symList.erase( theIter2 );
                symList.erase( theIter1 );

                theIter1 = symList.begin(); // start from the beginning again
                pSym = ( theIter1 == NULL ) ? NULL : (Symbol*)theIter1;
                continue;
            }
            theIter1 = theIter2;
        }

        theIter1++;
        pSym = ( theIter1 == NULL ) ? NULL : (Symbol*)theIter1;
    }
#else
    SYMBOL_LISTIterator theIter1 = symList.begin();
    SYMBOL_LISTIterator theIter2 = symList.begin(); // need this due to different semantics of "theIter2 = theIter1" in C++ and XORT... 
    Symbol pSym = theIter1.item();
    theIter2.next(); // move to next item

    while( pSym )
    {
        if( MEMBER_PTR(pSym)m_csName.Compare( cFRAME_ENTER ) == 0 )
        {
            Symbol pSym2 = theIter2.item();
        
            if( pSym2 && ( MEMBER_PTR(pSym2)m_csName.Compare( cFRAME_LEAVE ) == 0 ) )
            {
                SYMBOL_LISTIterator theIter = symList.erase( theIter1 );
                symList.erase( theIter );

                theIter1 = symList.begin(); // start from the beginning again
                theIter2 = symList.begin();
                pSym = theIter1.item();
                theIter2.next();
                continue;
            }
        }

        theIter1.next();
        pSym = theIter1.item();
        theIter2.next();
    }
#endif
}

void RemoveRedundandStackTransitionSymbols( SYMBOLLIST symList )
{
#ifdef CPP_COMPILER
    SYMBOL_LIST::iterator theIter = symList.begin();
    symbolref pSym = (Symbol*)theIter;
#else
    SYMBOL_LISTIterator theIter = symList.begin();
    Symbol pSym = theIter.next();
#endif
    while( pSym )
    {
        if( MEMBER_PTR(pSym)m_SymKind == sk_obj )
        {
            RemoveRedundandStackTransitionSymbols( MEMBER_PTR(pSym)m_listMembers );
        }
        else if( MEMBER_PTR(pSym)m_SymKind == sk_proc )
        {
            if( MEMBER_PTR(pSym)m_stackMembers.size() > 0 )
            {
                RemoveStkTarnsition( MEMBER_PTR(pSym)m_stackMembers );
            }
        }
#ifdef CPP_COMPILER
        theIter++;
        pSym = ( theIter == NULL ) ? NULL : (Symbol*)theIter;
#else
        pSym = theIter.next();
#endif
    }
}

#ifdef __XVM__
//////////////////////////////////////////////////////////////////////////
// XVM debugger related stuff
SymbolRef ValidateBreakpointPosition( SYMBOLLIST symList, dword dwLineNo, dword *pdwLineNoOut )
{
    // Commented out due to instruction representation changed
    /*
#ifdef CPP_COMPILER
    SYMBOL_LIST::iterator theIter = symList.begin();
    symbolref pSym = (Symbol*)theIter;
#else
    SYMBOL_LISTIterator theIter = symList.begin();
    Symbol pSym = theIter.next();
#endif
    while( pSym )
    {
        if( MEMBER_PTR(pSym)m_SymKind == sk_obj )
        {
            SymbolRef sym = ValidateBreakpointPosition( MEMBER_PTR(pSym)m_listMembers, dwLineNo, pdwLineNoOut );
            if( !sym.isNULL() )
                return sym;
        }
        else if( MEMBER_PTR(pSym)m_SymKind == sk_proc )
        {
            dword dwNumLines = MEMBER_PTR(pSym)m_arLinesInfo.count();
            if( dwNumLines > 0 )
            {
                dword dwStart = MEMBER_PTR(pSym)m_arLinesInfo.get( 0 );
                dword dwEnd   = MEMBER_PTR(pSym)m_arLinesInfo.get( dwNumLines-1 );

                if( dwStart <= dwLineNo && dwLineNo <= dwEnd ) // procedure found, bp is inside, validate line
                {
                    dword i, j;
                    for( i = 0; i < dwNumLines; ++i )
                    {
                        dword dwLine = MEMBER_PTR(pSym)m_arLinesInfo.get( i );
                        if( dwLine == dwLineNo )
                        {
                            *pdwLineNoOut = dwLine;
                            return DEREF(pSym);
                        }
                        if( dwLineNo < dwLine ) // small optimization :)
                            break;
                    }
                    // correct line in this case
                    i = 0;
                    for( j = 1; j < dwNumLines; ++j ) // compiler still does not support multiple expressions inside for statement...
                    {
                        dword dwLine1 = MEMBER_PTR(pSym)m_arLinesInfo.get( i );
                        dword dwLine2 = MEMBER_PTR(pSym)m_arLinesInfo.get( j );
                        if( dwLine1 < dwLineNo && dwLineNo < dwLine2 )
                        {
                            *pdwLineNoOut = dwLine2; // move breakpoint to the nearest valid position
                            return DEREF(pSym);
                        }
                        ++i;
                    }
                }
                else if( dwStart > dwLineNo )
                {
                    if( dwStart <= dwLineNo+2 ) { // user can set bp 2 lines up the procedure
                        *pdwLineNoOut = dwStart;
                        return DEREF(pSym);
                    }
                }
                else if( dwEnd < dwLineNo ) // or 2 lines down the proc
                {
                    if( dwEnd >= dwLineNo-2 ) {
                        *pdwLineNoOut = dwEnd;
                        return DEREF(pSym);
                    }
                }
            }
        }

#ifdef CPP_COMPILER
        theIter++;
        pSym = ( theIter == NULL ) ? NULL : (Symbol*)theIter;
#else
        pSym = theIter.next();
#endif
    }*/
    return getNULLSymbol();
}

dword GetInstructionIPFromSourceLine( SymbolRef symProc, dword dwLineNo )
{
    /*
    if( symProc.m_SymKind != sk_proc || symProc.m_Code.count() == 0 || symProc.m_arLinesInfo.count() == 0 )
        return -1;

    dword dwNumLines = symProc.m_arLinesInfo.count();
    if( dwNumLines == 0 ) // no debug information
        return -1; // will not switch to next procedure

    dword dwIP = 0;
    dword dwSize = symProc.m_Code.count();
    dword dwLineIdx = 0;

    while( dwIP < dwSize ) {
        InstructionData decData;
        if( !decode_instr( symProc.m_Code, dwIP, decData ) ) {
            return -1;
        }

        dword dwLine = symProc.m_arLinesInfo.get( dwLineIdx );
        if( dwLineNo == dwLine ) {
            return dwIP;
        }

        dwIP += decData.m_dwShiftToNext;
        ++dwLineIdx;
    }
    */
    return -1;
}

void Symbol::GenerateIPLineMap()
{
    /*
    if( m_dwFlags & f_iplinemap_gen )
        return;

    dword dwNumLines = m_arLinesInfo.count();
    if( dwNumLines == 0 ) // no debug information
        return; // will not switch to next procedure
    
    dword dwIP = 0;
    dword dwSize = m_Code.count();
    dword dwLineIdx = 0;
    dword dwPrevLine = -1;

    m_dwNumStatements = 0;
    m_mapIpLine.clear();

    while( dwIP < dwSize ) {
        InstructionData decData;
        if( !decode_instr_fast( m_Code, dwIP, decData ) ) {
            return;
        }

        dword dwLine = m_arLinesInfo.get( dwLineIdx );
        if( dwPrevLine != dwLine ) {
            m_mapIpLine[dwIP] = dwLine;
            m_dwNumStatements++;
            dwPrevLine = dwLine;
        }

        dwIP += decData.m_dwShiftToNext;
        ++dwLineIdx;
    }

    m_dwFlags |= f_iplinemap_gen;
    */
}

dword Symbol::GetLineFromIP( dword dwIP )
{
    MAP_IPTOLINE::iterator theIter = m_mapIpLine.find( dwIP );
    if( theIter != m_mapIpLine.end() )
        return theIter->second;
    return -1;
}
// TODO: CHECK!!! this might not be true!, same is used for stk transitions!
dword Symbol::GetArgumentsCount() // returns the number of arguments for sk_proc or 0
{
    if( m_SymKind != sk_proc )
        return 0;
    return m_listMembers.size() -1; // first is local scope marker
}

#endif // __XVM__
